#if !defined(WEBBY_SERVER_HXX)
#define WEBBY_SERVER_HXX

#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/function.hpp>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <poll.h>

#include <vector>
#include <set>
#include <queue>

#include <webby/message.hxx>
#include <webby/module.hxx>

namespace webby 
{

	typedef boost::shared_ptr< boost::thread > thread_ptr;
	typedef boost::shared_ptr< Message > message_ptr;

	struct FastCGIServiceInfo
	{
		FastCGIServiceInfo() : mPort(0) {}	
		FastCGIServiceInfo( unsigned short port ) : mPort( port ) {}

		unsigned short mPort;
	};

	struct FastCGITransaction
	{
		FastCGITransaction() : mClientSocket(0), mBufferSize(0) {}

		int mClientSocket;
		unsigned char mBuffer[1024*64];
		unsigned int mBufferSize;
	};

	class Server : public boost::enable_shared_from_this<Server>
	{
	public:
		friend class Message;
		friend class ReadSocketMessage;
		friend class BeginFastCGIMessage;	
		friend class FastCGIOutputMessage;

		Server();
		void start( unsigned int port = 80, unsigned int threads = 4 );
		bool isRunning() const;	
		void handleEvents();
		void threadStarted( unsigned int threadNum );
		void quit();

		void addFastCGIHandler( const std::string &extension, unsigned short port );
		void addModule( const std::string &moduleName );

	protected:
		bool mCanExit;
		bool mThreadsRunning;

		std::vector< thread_ptr > mThreads;

		fd_set read_set, write_set, except_set;
		int mServerSocket;

		// used for synchronizing queues
		boost::mutex mLock;
		boost::mutex mLocalLock;
		boost::condition mCondition;

		// 
		std::set< unsigned int > mSockets;

		std::queue< message_ptr > mThreadQueue;
		std::queue< message_ptr > mLocalThreadQueue;

		// map php to some handler
		std::map< std::string, FastCGIServiceInfo > mFastCGIHandlers;

		std::set< int > mSocketCloseSet;

		// maps sockets to individual transactions
		std::map< int, FastCGITransaction > mSocketToFastCGIMap;

		bool isFastCGI( const std::string &extension ) const;
		void handleFastCGIScript( const std::string &cgiType, const std::string &scriptName, int socket );
		void handleFastCGISocket( int socket, bool &erase );

		unsigned short mID;

		void addToThreadQueue( message_ptr );
		void addToLocalThreadQueue( message_ptr );
		void handleSocketClose( int clientSocket );

		std::vector< ModulePtr > mModules;
		std::map< int, pollfd > mPollMap;

	private:
		void handleServerAccept();
		void handleClientRead( int readSocket );
		void addFdToPollMap( int socket ) { pollfd fd = { socket, POLLERR | POLLIN | POLLOUT, 0 }; mPollMap[socket] = fd; }
	};
	
}

#endif
